package com.dongbao.action;

import com.dongbao.common.AwardedInfoConstant;
import com.dongbao.common.PluginModueType;
import com.dongbao.dialog.DHGToolWindow;
import com.dongbao.entity.PluginModueExamInfo;
import com.dongbao.util.FieldUtil;
import com.dongbao.util.ToolWindowUtil;
import com.esotericsoftware.minlog.Log;
import com.intellij.codeInsight.navigation.ClassImplementationsSearch;
import com.intellij.ide.util.frameworkSupport.AddFrameworkSupportDialog;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.file.PsiJavaDirectoryImpl;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.util.Query;
import net.sourceforge.pmd.*;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.XMLRenderer;
import net.sourceforge.pmd.util.ClasspathClassLoader;
import net.sourceforge.pmd.util.datasource.DataSource;
import net.sourceforge.pmd.util.datasource.FileDataSource;
import org.dom4j.Attribute;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.*;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.yaml.YAMLElementGenerator;
import org.jetbrains.yaml.psi.YAMLFile;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class DHGModulePluginAction extends AnAction {

    private static final Logger LOG = Logger.getInstance(DHGModulePluginAction.class);

    private List<PluginModueExamInfo> deductions=new ArrayList<PluginModueExamInfo>();

    private PMDConfiguration configuration;


    private List<RuleSet> ruleSets;


    @Override
    public void actionPerformed(AnActionEvent e) {
        deductions.clear();
        ProgressManager.getInstance().run(new Task.Backgroundable(e.getProject(), e.getPresentation().getText(), false) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                ApplicationManager.getApplication().runReadAction(
                        () -> {
                            runDetection(e,indicator);
                        }
                );
            }
        });

    }

    public void runDetection(AnActionEvent e,ProgressIndicator indicator){
        String moduleRootPath = ((PsiJavaDirectoryImpl)e.getData(LangDataKeys.PSI_ELEMENT_ARRAY)[0]).getVirtualFile().getPath();
        /* 读取该模块下面所有的文件 */
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
        GlobalSearchScope moduleScope = module.getModuleWithDependenciesAndLibrariesScope(false);
        Collection<VirtualFile> files = FilenameIndex.getAllFilesByExt(e.getProject(), "java", moduleScope);

        /* 加载插件化的检测规则 */
        initRules();
        /* 判断当前模块下是否还有模块 */
        VirtualFile parentPom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(moduleRootPath, MavenConstants.POM_XML));
        MavenProject project = MavenProjectsManager.getInstance(e.getProject()).findProject(parentPom);
        List<VirtualFile> existingModuleFiles = project.getExistingModuleFiles();
        /* 使用规则去跑这些的模块下面的java文件(可以只扫描待特定注解的文件,例如@Controller @DongBaoService) */

        /* 判断当前的模块是否在 application-develop.yml 的配置文件中添加到插件列表 */
        mainYmlDetection(project,e.getProject());

        if(existingModuleFiles.isEmpty()){
            /* 当前选择为根节点模块  */
            runRules(files,project,e.getProject(),e,indicator);
        } else{
            /* 遍历所有子模块 */
            for(VirtualFile childModule:existingModuleFiles){
                VirtualFile childPom = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(childModule.getParent().getPath(), MavenConstants.POM_XML));
                MavenProject childProject = MavenProjectsManager.getInstance(e.getProject()).findProject(childPom);

                runRules(files,childProject,e.getProject(),e,indicator);
            }
        }

        DHGToolWindow fastRequestToolWindow = ToolWindowUtil.getDHGToolWindow(e.getProject());
        fastRequestToolWindow.refreshPluginErrorInfos(deductions);
    }

    public void initRules(){

    }

    public void runRules(Collection<VirtualFile> files, MavenProject project,Project rootProject,AnActionEvent e,ProgressIndicator indicator){
        /* 判断当前所选模块的POM文件中是否按照规定添加了POM的必备引入工具 */
        long startTimeMillis = System.currentTimeMillis();
        pomSetting(project);
        /* 检测模块 service 下是否存在 插件的属性文件 */
        pluginConfig(project,e);
        /* 检测 Dao 层是否使用了 @org.apache.ibatis.annotations.Mapper 的注解 */
        daoRule(project,rootProject,e);
        /* 检测当前模块的 Controller 和 Service 还有 Dao 文件是否在同一个模块中 & 变量属性*/
        classUnifyModule(project,rootProject,e);
        /* 检测当前模块的类中声明的变量属性的注解是否使用正确 */
        filesAnno(project,rootProject,e);
        /* 检测当前模块的类中声明的变量属性的注解是否使用正确 */
        acrossModuleCite(project,rootProject,e,indicator);
        LOG.info("6666");


    }

    /**
     * 检测是否存在跨模块使用工具类的情况
     * */
    public void acrossModuleUtil(PsiClass checkClass,MavenProject project,Project rootProject,AnActionEvent e){
        /* TODO:查找方法中的工具类的调用 - 暂时不知道怎么写 先略过 */

    }

    /**
     * 检查当前的class中是否存在反射的调用
     * */
    public void acrossModuleReflection(List<PsiClass> psiAllClass,MavenProject project,Project rootProject,AnActionEvent event,ProgressIndicator indicator){
        /* 检查当前的class中是否存在反射的调用 */

        /* 加载 PMD 规则文件 */
        configuration = new PMDConfiguration();
        try{
            /* 首先我们创建一个PMDConfiguration. 这是当前指定规则集的唯一方法： */
            configuration.setMinimumPriority(RulePriority.MEDIUM);
            configuration.setRuleSets("rulesets/java/dhgModuleRules.xml");
            /* 为了支持类型解析，PMD 还需要访问已编译的类和依赖项。这称为“auxclasspath”，也在此处配置。注意：您可以:在 Unix 系统或;Windows 下指定多个以 分隔的类路径。 */
            configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
            /* 然后我们需要加载规则集。这是通过使用配置完成的，考虑到最低优先级： */
            RuleSetLoader ruleSetLoader = RuleSetLoader.fromPmdConfig(configuration);
            ruleSets = ruleSetLoader.loadFromResources(Arrays.asList(configuration.getRuleSets().split(",")));
            /* PMD 对DataSource. 您可以组装一个自己的列表FileDataSource，例如 */
            List<DataSource> filesDataSet = new ArrayList<>();
            for(int i=0;i<psiAllClass.size();i++){
                PsiClass classFile = psiAllClass.get(i);
                filesDataSet.clear();
                filesDataSet.add(new FileDataSource(new File(classFile.getContainingFile().getVirtualFile().getPath())));

                indicator.setText("正在执行PMD分析文件["+classFile.getName()+"]("+(i+1)+"/"+psiAllClass.size()+")");

                /* 对于报告，您可以使用内置渲染器，例如XMLRenderer或自定义渲染器实现 Renderer. 请注意，您必须通过设置合适的Writer并调用start(). PMD 运行后，您需要调用 end()和flush()。那么你的作者应该已经收到了所有的输出。 */
                StringWriter rendererOutput = new StringWriter();
                Renderer xmlRenderer = new XMLRenderer("UTF-8");
                xmlRenderer.setWriter(rendererOutput);
                xmlRenderer.start();
                /* 现在，所有的准备工作都完成了，可以执行 PMD 了。这是通过调用 PMD.processFiles(...). 此方法调用采用配置、规则集、要处理的文件和渲染器列表。如果您不想使用任何渲染器，请提供一个空列表。注意：需要明确关闭 auxclasspath。否则类或 jar 文件可能会保持打开状态并泄漏文件资源。 */
                PMD.processFiles(configuration, ruleSets, filesDataSet, Collections.singletonList(xmlRenderer));
                /* 调用后，您需要通过end()和完成渲染器flush()。然后你可以检查渲染的输出。 */
                xmlRenderer.end();
                xmlRenderer.flush();
                String result = rendererOutput.toString();
                /* 解析结果到错误信息集合中 */
                parsingPMDInfo(result);

            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            ClassLoader auxiliaryClassLoader = configuration.getClassLoader();
            if (auxiliaryClassLoader instanceof ClasspathClassLoader) {
                try {
                    ((ClasspathClassLoader) auxiliaryClassLoader).close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 解析PMD处理的结果到错误信息集合中
     * */
    public void parsingPMDInfo(String result){
        org.dom4j.Document document = null;
        try {
            document = DocumentHelper.parseText(result);
            org.dom4j.Element rootElement = document.getRootElement();
            List<org.dom4j.Element> files = rootElement.elements("file");
            for(org.dom4j.Element childElement:files){
                if(childElement == null){
                    return ;
                }
                for (int i = 0; i < childElement.attributeCount(); i++) {
                    Attribute name = childElement.attribute(i);
                    String names = name.getName();
                    String value =  childElement.attributeValue(names);
//                VirtualFile afterFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(value));
                    /* 遍历子节点获取检测数据 */
                    List<org.dom4j.Element> violations = childElement.elements("violation");
                    /* 遍历获取节点属性 */
                    for(org.dom4j.Element violation:violations){
                        PluginModueExamInfo modueExamInfo=new PluginModueExamInfo();
                        VirtualFile afterFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(value);
                        modueExamInfo.setVirtualFile(afterFile);
                        modueExamInfo.setFileName(afterFile.getName());

                        for(int j=0;j<violation.attributeCount();j++){
                            Attribute violationAttr = violation.attribute(j);
                            String violationAttrName = violationAttr.getName();
                            String violationAttrValue = violationAttr.getValue();
                            //                    System.out.println("violation====="+violationAttrName+":"+violationAttrValue+"  ");
                            switch (violationAttrName){
                                case "beginline":
                                    modueExamInfo.setStartLine(Integer.valueOf(violationAttrValue));
                                    break;
                                case "endline":
                                    modueExamInfo.setEndLine(Integer.valueOf(violationAttrValue));
                                    break;
                                case "rule":
//                                awardedInfo.setRule(violationAttrValue);
                                    break;
                                case "ruleset":
//                                awardedInfo.setRuleset(violationAttrValue);
                                    break;
                                case "package":
//                                awardedInfo.setJavaPackage(violationAttrValue);
                                    break;
                                case "class":
//                                awardedInfo.setJavaClass(violationAttrValue);
                                    break;
                                case "method":
//                                awardedInfo.setJavaMethod(violationAttrValue);
                                    break;
                                case "externalInfoUrl":
//                                awardedInfo.setExternalInfoUrl(violationAttrValue);
                                    break;
                                case "priority":
//                                awardedInfo.setPriority(violationAttrValue);
                                    break;
                            }
                        }
                        /* 获取检测内容信息 */
                        String text = violation.getText();
                        modueExamInfo.setDesc(text);
                        deductions.add(modueExamInfo);
                    }
                }
            }


        } catch (DocumentException e) {
            e.printStackTrace();
        }
        LOG.info("666");
    }

    /**
     * 检测是否存在跨模块引用Biz或工具类的情况
     * */
    public void acrossModuleCite(MavenProject project,Project rootProject,AnActionEvent e,ProgressIndicator indicator){
        long startTimeMillis = System.currentTimeMillis();
        /* 获取所有的 Controller 和 Service  */
        Query<PsiClass> baseControllerExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-common","com.dongbao.core.base.BaseController");
        Query<PsiClass> baseCommonControllerExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-base","com.dongbao.web.base.BaseCommonController");
        Query<PsiClass> baseServiceExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-service","com.dongbao.service.base.BaseServiceImpl");
        List<PsiClass> psiAllClass = new ArrayList<PsiClass>();
        baseControllerExtClass.forEach(item->{
            checkAcrossModuleCite(item,project,rootProject);
            /* 检查使用的工具类是否有存在跨模块的情况 */
            acrossModuleUtil(item,project,rootProject,e);
            psiAllClass.add(item);
        });
        /* 遍历所有Class 获取class中的注入对象 */
        baseCommonControllerExtClass.forEach(item->{
            checkAcrossModuleCite(item,project,rootProject);
            /* 检查使用的工具类是否有存在跨模块的情况 */
            acrossModuleUtil(item,project,rootProject,e);
            psiAllClass.add(item);
        });
        /* 获取当前Class中所有的注入对象 */
        baseServiceExtClass.forEach(item->{
            checkAcrossModuleCite(item,project,rootProject);
            /* 检查使用的工具类是否有存在跨模块的情况 */
            acrossModuleUtil(item,project,rootProject,e);
            psiAllClass.add(item);
        });
        /* 使用PMD扫描检测下面的所有class文件 */
        acrossModuleReflection(psiAllClass,project,rootProject,e,indicator);

    }

    /**
     * 检测 Class 中的变量或者工具类是否跨模块引用
     * */
    public void checkAcrossModuleCite(PsiClass checkClass,MavenProject project,Project rootProject){
        /**
         * 检测是否存在别的模块的变量并且使用的不是接口的方式
         * */
        PsiField[] fields = checkClass.getFields();
        for(PsiField field:fields){
            if( field.getType().getCanonicalText().contains("com.dongbao")){
                try{
                    /* 获取当前属性所在的模块  */
                    Module moduleForFile = ProjectFileIndex.getInstance(rootProject).getModuleForFile(FieldUtil.getFieldClass(field).getContainingFile().getVirtualFile());
                    if(moduleForFile == null){
                        /* 等于 null 则是别的模块的类,并且没有拉取别的模块的代码 直接判断当前的变量是否是接口*/
                    }else if(moduleForFile != null && !moduleForFile.getModuleFile().getParent().getParent().getName().equals(project.getParentId().getArtifactId()) && !moduleForFile.getModuleFile().getParent().getName().contains("hcmoa-")){
                        /* 不是自己模块的东西 并且不属于主模块的 则判断是否是接口 */
                        final PsiClassType operandClassType = (PsiClassType)field.getType();
                        PsiClass resolve = operandClassType.resolve();
                        boolean isInterface = resolve.isInterface();
                        if(!isInterface){
                            Document document = PsiDocumentManager.getInstance(checkClass.getProject()).getDocument(checkClass.getContainingFile());
                            int lineNumber = document.getLineNumber(field.getTextOffset());
                            packDeduction(project.getName(),
                                    checkClass.getContainingFile().getVirtualFile().getPath(),
                                    checkClass.getContainingFile().getVirtualFile(),
                                    lineNumber,
                                    lineNumber,
                                    "声明的【"+field.getName()+"】是别的模块的引用,请使用接口的方式使用 ",
                                    "声明的【"+field.getName()+"】是别的模块的引用,请使用接口的方式使用  ",
                                    PluginModueType.FILE_TYPE);
                        }
                        LOG.info("666");
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 检测当前模块的类中声明的变量属性的注解是否使用正确
     * @Autowired
     * 引自己模块的对象，hcmoa和其他普通模块都适用
     * @DongBaoResource
     * 引用类不是自己模块，也不是hcmoa模块，hcmoa和其他普通模块都适用
     * @DongBaoResource(type = 1)
     * 非hcmoa模块引hcmoa模块的对象，只适用于非hcmoa模块
     * 注意：引用对象以实现类为主，不是接口
     * */
    public void filesAnno(MavenProject project,Project rootProject,AnActionEvent e){
        /* 获取所有的 Controller 和 Service  */
        Query<PsiClass> baseControllerExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-common","com.dongbao.core.base.BaseController");
        Query<PsiClass> baseCommonControllerExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-base","com.dongbao.web.base.BaseCommonController");
        Query<PsiClass> baseServiceExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-service","com.dongbao.service.base.BaseServiceImpl");
        baseControllerExtClass.forEach(item->{
            checkInjectObject(item,project,rootProject);
        });
        /* 遍历所有Class 获取class中的注入对象 */
        baseCommonControllerExtClass.forEach(item->{
            checkInjectObject(item,project,rootProject);
        });
        /* 获取当前Class中所有的注入对象 */
        baseServiceExtClass.forEach(item->{
            checkInjectObject(item,project,rootProject);
        });
    }

    /**
     * 检查 class里面声明的注入对象
     * */
    public void checkInjectObject(PsiClass checkClass,MavenProject project,Project rootProject){
        /* 获取 class 中的声明的属性 */
        PsiField[] fields = checkClass.getFields();
        /* 检查属性的注解是否都是正确的 */
        for(PsiField field:fields){
            /* 只有东宝包的内容才需要判断扫描 */
            if(field.getType().getCanonicalText().contains("com.dongbao")){
                PsiAnnotation[] annotations = field.getAnnotations();
                /* 判断是否使用了 @Autowired @DongBaoResource 的注解 */
                Boolean isInject = false;
                String curAnnotation = "";
                for(PsiAnnotation annotation:annotations){
                    if(annotation.getText().equals("@Autowired")||annotation.getText().contains("@DongBaoResource")){
                        curAnnotation = annotation.getText().replace(" ","");
                        isInject = true;
                    }
                }
                /* 判断使用的注解是否正确 */
                if(isInject){

                    Document document = PsiDocumentManager.getInstance(checkClass.getProject()).getDocument(checkClass.getContainingFile());
                    int lineNumber = document.getLineNumber(field.getTextOffset());
                    /* 判断如果是接口则查找这个接口的实现类  */
                    PsiClass fieldClass = FieldUtil.getFieldClass(field);
                    if(FieldUtil.checkFieldIsInterface(field)){
                        if(field.getName().equals("recMsgTemplateService")){
                            Log.info("666");
                        }
                        /* 如果是接口则查找实现类 */
                        boolean result = ClassImplementationsSearch.processImplementations(fieldClass, element ->
                        {
                            if (element instanceof PsiClass) {
                                checkClassInjectObject(field, lineNumber, checkClass, project, rootProject, (PsiClass) element);
                                return false;
                            }
                            return true;
                        }, GlobalSearchScope.allScope(rootProject));
                        Log.info("666");
                        if(result){
                            /* 在当前拉的代码和主模块中没有找到 则认为是其他插件模块的类,应当使用 @DongBaoResource 注解 */
                            if(!curAnnotation.equals("@DongBaoResource")){
                                packDeduction(project.getName(),
                                        checkClass.getContainingFile().getVirtualFile().getPath(),
                                        checkClass.getContainingFile().getVirtualFile(),
                                        lineNumber,
                                        lineNumber,
                                        "声明的【"+field.getName()+"】不属于本模块与主模块,应当使用 @DongBaoResource 注解 ",
                                        "声明的【"+field.getName()+"】不属于本模块与主模块,应当使用 @DongBaoResource 注解  ",
                                        PluginModueType.FILE_TYPE);
                            }
                        }
                    }else{
                        /* 不是接口 直接去查找类 */
                        checkClassInjectObject(field,lineNumber,checkClass,project,rootProject,fieldClass);
                    }

                }
            }
        }
    }

    public void checkClassInjectObject(PsiField field,int lineNumber,PsiClass checkClass,MavenProject project,Project rootProject,PsiClass fieldRealClass){

        PsiAnnotation[] annotations = field.getAnnotations();
        /* 判断是否使用了 @Autowired @DongBaoResource 的注解 */
        String curAnnotation = "";
        for(PsiAnnotation annotation:annotations){
            if(annotation.getText().equals("@Autowired")||annotation.getText().contains("@DongBaoResource")){
                curAnnotation = annotation.getText().replace(" ","");
            }
        }

        VirtualFile fieldVirtualFile = fieldRealClass.getContainingFile().getVirtualFile();
        Module moduleForFile = ProjectFileIndex.getInstance(rootProject).getModuleForFile(fieldVirtualFile);
        try{
            if(moduleForFile == null && !curAnnotation.equals("@DongBaoResource")){
                /* 这个类在别的模块,没有拉别的模块的代码，就会获取到NULL ,检查是否用的 @DongBaoResource 注解并且没有带1的条件*/
                /* 当前类在自己本模块 应该使用 @Autowired 的注解 */
                packDeduction(project.getName(),
                        checkClass.getContainingFile().getVirtualFile().getPath(),
                        checkClass.getContainingFile().getVirtualFile(),
                        lineNumber,
                        lineNumber,
                        "声明的【"+field.getName()+"】不属于本模块与主模块,应当使用 @DongBaoResource 注解 ",
                        "声明的【"+field.getName()+"】不属于本模块与主模块,应当使用 @DongBaoResource 注解  ",
                        PluginModueType.FILE_TYPE);
            }else if(moduleForFile != null && !moduleForFile.getModuleFile().getParent().getParent().getName().equals(project.getParentId().getArtifactId()) && !moduleForFile.getModuleFile().getParent().getName().contains("hcmoa-") && !curAnnotation.equals("@DongBaoResource")){
                /* 不属于自己模块 并且不属于主模块的内容 */
                packDeduction(project.getName(),
                        checkClass.getContainingFile().getVirtualFile().getPath(),
                        checkClass.getContainingFile().getVirtualFile(),
                        lineNumber,
                        lineNumber,
                        "声明的【"+field.getName()+"】不属于本模块与主模块,应当使用 @DongBaoResource 注解 ",
                        "中声明的【"+field.getName()+"】不属于本模块与主模块,应当使用 @DongBaoResource 注解  ",
                        PluginModueType.FILE_TYPE);
            }else if(moduleForFile != null && moduleForFile.getModuleFile().getParent().getName().contains("hcmoa-") && !curAnnotation.equals("@DongBaoResource(type=1)")){
                /* 引入的主模块的东西 但是没有使用 @DongBaoResource(type=1) 的注解 */
                packDeduction(project.getName(),
                        checkClass.getContainingFile().getVirtualFile().getPath(),
                        checkClass.getContainingFile().getVirtualFile(),
                        lineNumber,
                        lineNumber,
                        "声明的【"+field.getName()+"】属于主模块的内容,应当使用@DongBaoResource(type=1) 注解 ,注意应该使用 type=1",
                        "声明的【"+field.getName()+"】属于主模块的内容,应当使用@DongBaoResource(type=1) 注解 ,注意应该使用 type=1 ",
                        PluginModueType.FILE_TYPE);
            }else if(moduleForFile != null && moduleForFile.getModuleFile().getParent().getParent().getName().equals(project.getParentId().getArtifactId()) && !curAnnotation.equals("@Autowired")){
                /* 当前类在自己本模块 应该使用 @Autowired 的注解 */
                packDeduction(project.getName(),
                        checkClass.getContainingFile().getVirtualFile().getPath(),
                        checkClass.getContainingFile().getVirtualFile(),
                        lineNumber,
                        lineNumber,
                        "声明的【"+field.getName()+"】属于自己本模块的,应当使用 @Autowired 注解 ",
                        "声明的【"+field.getName()+"】属于自己本模块的,应当使用 @Autowired 注解 ",
                        PluginModueType.FILE_TYPE);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 查找模块下指定的继承类
     * */
    public Query<PsiClass> findClassByBaseInModule(MavenProject project,Project rootProject,AnActionEvent e,String baseClassModuleName,String baseClassAllName){
        String moduleName = project.getName();
        Module serviceModule = ModuleManager.getInstance(e.getProject()).findModuleByName(moduleName);
        GlobalSearchScope moduleScope = GlobalSearchScope.moduleScope(serviceModule);

        Module hcmoaCommon = ModuleManager.getInstance(e.getProject()).findModuleByName(baseClassModuleName);
        GlobalSearchScope hcmoaCommonScope = GlobalSearchScope.moduleScope(hcmoaCommon);
        PsiClass baseControllerClass = JavaPsiFacade.getInstance(rootProject).findClass(baseClassAllName,hcmoaCommonScope);
        Query<PsiClass> baseControllerExtClass = ClassInheritorsSearch.search(baseControllerClass, moduleScope, true);
        return baseControllerExtClass;
    }


    /**
     * 检测当前模块的 Controller 和 Service 还有 Dao 文件是否在同一个模块中
     * */
    public void classUnifyModule(MavenProject project,Project rootProject,AnActionEvent e){
        /* 查找当前模块的所有 Controller 类  */
        String moduleName = project.getName();
        Module serviceModule = ModuleManager.getInstance(e.getProject()).findModuleByName(moduleName);
        GlobalSearchScope moduleScope = GlobalSearchScope.moduleScope(serviceModule);

        Query<PsiClass> baseControllerExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-common","com.dongbao.core.base.BaseController");
        Query<PsiClass> baseCommonControllerExtClass = findClassByBaseInModule(project,rootProject,e,"hcmoa-base","com.dongbao.web.base.BaseCommonController");

        /* 遍历查询到的两个Class 判断Service与Dao是否在同一层 */
        baseControllerExtClass.forEach(item->{
            LOG.info("666");
        });
        baseCommonControllerExtClass.forEach(item->{
            /* 解析出当前控制器的Service */
            String serviceClassName = "";
            if(item.getExtendsList().getLastChild().getLastChild().getChildren().length!=0){
                serviceClassName = item.getExtendsList().getLastChild().getLastChild().getChildren()[1].getText();
            }else{
                serviceClassName = item.getName().substring(0,item.getName().length()-10)+"ServiceImpl";;
            }
            /* 当前模块搜索这个 Service 文件 */
//            JavaPsiFacade.getInstance(rootProject).findClasses("com.dongbao.web.base.BaseCommonController",hcmoaBaseScope)
            String serviceName = serviceClassName.substring(1,serviceClassName.length())+"Impl.java";
            Collection<VirtualFile> files = FilenameIndex.getVirtualFilesByName(e.getProject(), serviceName, moduleScope);
            if(files.isEmpty()){
                Document document = PsiDocumentManager.getInstance(item.getProject()).getDocument(item.getContainingFile());
                int lineNumber = document.getLineNumber(item.getTextOffset());

                packDeduction(moduleName,
                        item.getContainingFile().getVirtualFile().getPath(),
                        item.getContainingFile().getVirtualFile(),
                        lineNumber,
                        lineNumber,
                        "请在【"+moduleName+"】模块中根据控制器【"+item.getName()+"】未找到对应Service,检索时使用 Service 全名["+serviceName+"] ",
                        "请在【"+moduleName+"】模块中根据控制器【"+item.getName()+"】未找到对应Service,检索时使用 Service 全名["+serviceName+"] ",
                        PluginModueType.FILE_TYPE);
            }
            /* 判断当前文件是否是接口类 */
            for(VirtualFile file:files){/* 当前模块搜索这个 Dao 文件 */
                String daoName = file.getName().substring(1,file.getName().length())+"Dao.java";
                if(file.getName().contains("ServiceImpl.java")){
                    daoName = file.getName().substring(0,file.getName().length()-16)+"Dao.java";
                }
                Collection<VirtualFile> daoFiles = FilenameIndex.getVirtualFilesByName(e.getProject(),daoName, moduleScope);
                if(daoFiles.isEmpty()){
                    Document document = PsiDocumentManager.getInstance(item.getProject()).getDocument(item.getContainingFile());
                    int lineNumber = document.getLineNumber(item.getTextOffset());
                    packDeduction(moduleName,
                            item.getContainingFile().getVirtualFile().getPath(),
                            item.getContainingFile().getVirtualFile(),
                            lineNumber,
                            lineNumber,
                            "请在【"+moduleName+"】模块中根据控制器【"+item.getName()+"】未找到对应Dao,检索时使用 Dao 全名["+daoName+"] ",
                            "请在【"+moduleName+"】模块中根据控制器【"+item.getName()+"】未找到对应Dao,检索时使用 Dao 全名["+daoName+"] ",
                            PluginModueType.FILE_TYPE);
                }
                LOG.info("666");
            }
        });

    }

    /**
     * 检测模块中的Dao文件是否按照条件规则
     * */
    public void daoRule(MavenProject project,Project rootProject,AnActionEvent e){
        /* 在当前模块范围内获取所有的Dao文件 */
        String moduleName = project.getName();
        Module serviceModule = ModuleManager.getInstance(e.getProject()).findModuleByName(moduleName);
        GlobalSearchScope moduleScope = GlobalSearchScope.moduleScope(serviceModule);

        Module hcmoaCommon = ModuleManager.getInstance(e.getProject()).findModuleByName("hcmoa-common");
        GlobalSearchScope hcmoaCommonScope = GlobalSearchScope.moduleScope(hcmoaCommon);

        PsiClass psiClass = JavaPsiFacade.getInstance(rootProject).findClass("com.dongbao.core.base.dao.BaseDao",hcmoaCommonScope);
        Query<PsiClass> query = ClassInheritorsSearch.search(psiClass, moduleScope, true);
        final StringBuilder stringBuilder = new StringBuilder();
        query.forEach(item->{
            PsiAnnotation annotation = item.getAnnotation("org.apache.ibatis.annotations.Mapper");
            if(annotation==null){
                Document document = PsiDocumentManager.getInstance(psiClass.getProject()).getDocument(psiClass.getContainingFile());
                int lineNumber = document.getLineNumber(item.getTextOffset());
                packDeduction(moduleName,
                        item.getContainingFile().getVirtualFile().getPath(),
                        item.getContainingFile().getVirtualFile(),
                        lineNumber,
                        lineNumber,
                        "请在【"+item.getName()+"】的Dao文件头部增加 @org.apache.ibatis.annotations.Mapper 的注解 ",
                        "请在【"+item.getName()+"】的Dao文件头部增加 @org.apache.ibatis.annotations.Mapper 的注解 ",
                        PluginModueType.FILE_TYPE);
            }
        });


//        PsiPackage aPackage = JavaPsiFacade.getInstance(rootProject).findPackage("com.dongbao."+project.getParentId().getArtifactId().replace("dhg-","")+".mapper");
//        PsiClass[] classes = aPackage.getClasses();
//        /* 遍历所有Dao文件判断是否使用了注解 */
//        for(PsiClass daoFile:classes){
//            PsiAnnotation[] annotations = daoFile.getAnnotations();
//            LOG.info("666");
//        }
        LOG.info("666");
    }

    public void pluginConfig(MavenProject project,AnActionEvent e){
//        PsiFile[] filesByName = PsiShortNamesCache.getInstance(rootProject).getFilesByName("");
        /* 检查是否存在插件的入口类 BasePlugin */
        String moduleName = project.getName();
        /* 此规则只对 service 进行处理 */
        if(moduleName.contains("-service")){
            Module serviceModule = ModuleManager.getInstance(e.getProject()).findModuleByName(moduleName);
            GlobalSearchScope moduleScope = GlobalSearchScope.moduleScope(serviceModule);
            PsiFile[] filesByName = FilenameIndex.getFilesByName(e.getProject(), "BasicPlugin.java", moduleScope);
            if(filesByName.length==0){
                packDeduction(moduleName,
                        project.getPath(),
                        project.getFile(),
                        0,
                        0,
                        "请在【"+moduleName+"】中添加插件入口类,继承 BasicPlugin ",
                        "请在【"+moduleName+"】中添加插件入口类,继承 BasicPlugin ",
                        PluginModueType.MODULE_TYPE);
            }
            /* 检查是否存在插件的配置文件 */
            PsiFile[] pluginPropFiles = FilenameIndex.getFilesByName(e.getProject(), "plugin.properties", moduleScope);
            if(pluginPropFiles.length==0){
                packDeduction(moduleName,
                        project.getPath(),
                        project.getFile(),
                        0,
                        0,
                        "请在【"+moduleName+"】中添加插件配置文件 【plugin.properties】 到resource目录下",
                        "请在【"+moduleName+"】中添加插件配置文件 【plugin.properties】 到resource目录下",
                        PluginModueType.MODULE_TYPE);
            }

            /* 检查是否存在插件的 PluginConfig 配置类 */
            PsiFile[] pluginConfigFiles = FilenameIndex.getFilesByName(e.getProject(), "PluginConfig.java", moduleScope);
            if(pluginConfigFiles.length==0){
                packDeduction(moduleName,
                        project.getPath(),
                        project.getFile(),
                        0,
                        0,
                        "请在【"+moduleName+"】中添加插件 【PluginConfig.java】 配置类 ",
                        "请在【"+moduleName+"】中添加插件 【PluginConfig.java】 配置类 ",
                        PluginModueType.MODULE_TYPE);
            }
            /* 检查是否存在插件的 MybatisPlusConfig 配置类 */
            PsiFile[] MybatisPlusConfigFiles = FilenameIndex.getFilesByName(e.getProject(), "MybatisPlusConfig.java", moduleScope);
            if(MybatisPlusConfigFiles.length==0){
                packDeduction(moduleName,
                        project.getPath(),
                        project.getFile(),
                        0,
                        0,
                        "请在【"+moduleName+"】中添加插件 【MybatisPlusConfig.java】 配置类 ",
                        "请在【"+moduleName+"】中添加插件 【MybatisPlusConfig.java】 配置类 ",
                        PluginModueType.MODULE_TYPE);
            }
            LOG.info("6666");
        }
    }

    /**
     * 判断当前的模块是否在 application-develop.yml 的配置文件中添加到插件列表
     * */
    public void mainYmlDetection(MavenProject project,Project rootProject){
        /* 获取到当前选择模块的主模块 */
        String artifactId = project.getParentId().getArtifactId();
        /* 读取主项目的 YML文件 找到插件的列表,判断是否在里面 */
        MavenModel result = new MavenModel();
        result.setMavenId(new MavenId("com.dongbao","hcmoa-main",project.getParentId().getVersion()));

        MavenProject hcmoaMain = MavenProjectsManager.getInstance(rootProject).findProject(new MavenId("com.dongbao", "hcmoa-main", project.getParentId().getVersion()));
//        Map<String, String> map = PropertiesUtil.loadProperties(new StringReader(hcmoaMain.getParentId().pa));
        if(hcmoaMain==null){
//            Messages.showErrorDialog(myTabbedPane.getComponent(),"当前项目未检测到hcmoa-main的模块,请刷新Maven依赖后继续。");
//            HintManager.getInstance().showErrorHint( FileEditorManager.getInstance(rootProject).getSelectedTextEditor(),"当前项目未检测到hcmoa-main的模块,请刷新Maven依赖后继续。");
            ApplicationManager.getApplication().invokeLater(() -> {
                ValidationInfo validationInfo = new ValidationInfo("当前项目未检测到hcmoa-main的模块,请刷新Maven依赖后继续。");
                Messages.showMessageDialog(validationInfo.message,"提示", Messages.getInformationIcon());
            });
            return ;
        }
        MavenResource mavenResource = hcmoaMain.getResources().stream().filter(item -> {
            return item.getIncludes().contains("application-${profileActive}.yml")||item.getIncludes().contains("application-develop.yml");
        }).findAny().orElse(null);
        String projectPropities = mavenResource.getDirectory()+"/application-develop.yml";
//        String value = YamlUtil.getValue("plugin.pluginPath", projectPropities);

//        File file = new File(projectPropities);
        byte[] bytes = new byte[0];
        try {
            bytes = Files.readAllBytes(Paths.get(projectPropities));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String content = new String(bytes, StandardCharsets.UTF_8);
        final YAMLFile tempFile = YAMLElementGenerator.getInstance(rootProject).createDummyYamlWithText(content);
        PsiElement[] children = tempFile.getChildren()[1].getChildren()[0].getChildren();
        Boolean ymlResult = false;
        for(int i=0;i<children.length;i++){
            PsiElement childrenElement = children[i];
            if(childrenElement.getText().contains("pluginPath")){
                PsiElement pluginRoowNode = childrenElement.getChildren()[0];
                for(PsiElement childElement:pluginRoowNode.getChildren()){
                    if(childElement.getText().contains("pluginPath")){
                        String pluginYml = childElement.getText();
                        ymlResult = pluginYml.contains(project.getFinalName());
                        break;
                    }
                }
                if(!ymlResult){
                    VirtualFile developYMLFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(projectPropities);;
                    packDeduction(tempFile.getName(),
                            developYMLFile.getPath(),
                            developYMLFile,
                            0,
                            0,
                            "需要在主模块 hcmoa-main 的配置文件中增加对"+project.getParentId().getArtifactId()+"模块的引入",
                            "需要在主模块 hcmoa-main 的配置文件中增加对"+project.getParentId().getArtifactId()+"模块的引入",
                            PluginModueType.FILE_TYPE);
                }
            }
        }
        LOG.info("6666");


    }

    /**
     * 检测pom中是否引入了 hcmoa-web 和 build 插件
     * */
    public void pomSetting(MavenProject project){
        String name = project.getName();
        Map<String, String> modelMap = project.getModelMap();

        VirtualFile projectPom = LocalFileSystem.getInstance().refreshAndFindFileByPath(project.getPath());
        if(name.contains("-api")){
            /* 检查POM文件中是否有引入了 hcmoa-base */
            List<MavenArtifact> hcmoaBaseArtifact = project.findDependencies("com.dongbao","hcmoa-base");
            if(hcmoaBaseArtifact.isEmpty()){
                packDeduction(name,
                        projectPom.getPath(),
                        projectPom,
                        0,
                        0,
                        "需要在模块的api层引入 hcmoa-base 的依赖",
                        "需要在模块的api层引入 hcmoa-base 的依赖",
                        PluginModueType.FILE_TYPE);
            }
        }
        if(name.contains("-service")){
            /* 检查POM文件中是否有引入了 打包plugins,并且是否是按照规则 */
            List<MavenPlugin> plugins = project.getPlugins();
            // todo:此处还有些问题,可以获取到主项目的内容,导致一直都会有这个插件
            Element pluginConfiguration = project.getPluginConfiguration("org.apache.maven.plugins", "maven-jar-plugin");
            if(pluginConfiguration==null){
                packDeduction(name,
                        projectPom.getPath(),
                        projectPom,
                        0,
                        0,
                        "需要在模块的service层引入 maven-jar-plugin ,并配置输出路径 ,参考地址 \\\\192.168.2.206\\研发用文档\\开发资料\\插件模块",
                        "需要在模块的service层引入 maven-jar-plugin ,并配置输出路径 ,参考地址 \\\\192.168.2.206\\研发用文档\\开发资料\\插件模块",
                        PluginModueType.FILE_TYPE);
            }
            LOG.info("6666");
        }
        LOG.info("6666");
    }

    public void packDeduction(String moduleName,
                              String path,
                              VirtualFile virtualFile,
                              Integer beginline,
                              Integer endline,
                              String desc,
                              String suggest,
                              Integer type){
        PluginModueExamInfo examInfo = new PluginModueExamInfo();
        examInfo.setModuleName(moduleName);
        examInfo.setFileName(virtualFile.getName());
        examInfo.setPath(path);
        examInfo.setVirtualFile(virtualFile);
        examInfo.setStartLine(beginline);
        examInfo.setEndLine(endline);
        examInfo.setDesc(desc);
        examInfo.setSuggest(suggest);
        examInfo.setType(type);
        deductions.add(examInfo);
    }

    @Override
    public void update(@NotNull final AnActionEvent e) {
        Module module = e.getData(LangDataKeys.MODULE_CONTEXT);
        try{
            boolean enable = module != null && AddFrameworkSupportDialog.isAvailable(module);
            if (ActionPlaces.isPopupPlace(e.getPlace())) {
                e.getPresentation().setVisible(enable);
            }
            else {
                e.getPresentation().setEnabled(enable);
            }
        }catch (Exception exce){
            e.getPresentation().setEnabled(true);
        }
    }

}
